package cn.t.listener.user;



import cn.t.core.enums.base.BaseStatusEnum;
import cn.t.enums.user.PassportTypeEnum;
import cn.t.enums.user.UpdateEventTypeEnum;
import cn.t.model.user.CostCenterDO;
import cn.t.model.user.CustomerFirmDO;
import cn.t.model.user.CustomerIndividualDO;
import cn.t.model.user.ParticipantInfoDO;
import cn.t.model.user.ParticipantRoleDO;
import cn.t.model.user.RoleInfoDO;
import cn.t.model.user.UserInfoDO;
import cn.t.model.user.UserPassportDO;
import cn.t.model.user.UserQueryDO;
import cn.t.service.user.CostCenterService;
import cn.t.service.user.CustomerFirmService;
import cn.t.service.user.CustomerIndividualService;
import cn.t.service.user.ParticipantInfoService;
import cn.t.service.user.ParticipantRoleService;
import cn.t.service.user.RoleInfoService;
import cn.t.service.user.UserInfoService;
import cn.t.service.user.UserPassportService;
import cn.t.service.user.UserQueryService;
import cn.t.user.event.UserQueryUpdateEvent;
import cn.t.vo.user.FirmVO;
import cn.t.vo.user.IndividualVO;
import cn.t.vo.user.ParticipantVO;
import cn.t.vo.user.PassportVO;
import cn.t.vo.user.RoleVO;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author l
 */
@Slf4j
@Async
@Component
public class UserQueryUpdateEventListener implements ApplicationListener<UserQueryUpdateEvent> {
    @Override
    public void onApplicationEvent(UserQueryUpdateEvent event) {

        IndividualVO individualVO;
        PassportVO passportVO;
        List<FirmVO> firms;

        UserQueryDO template = new UserQueryDO();
        template.setId(event.getUserId());

        ObjectMapper objectMapper = new ObjectMapper();

        if (UpdateEventTypeEnum.DELETE.equals(event.getPassportChanged())) {
            userQueryService.removeById(event.getUserId());
            return;
        }

        UserInfoDO userinfoDO = userInfoService.findById(event.getUserId());
        if (userinfoDO == null || userinfoDO.getId() == null || !userinfoDO.getId().equals(event.getUserId())) {
            userQueryService.disableUserQuery(event.getUserId());
            return;
        }

        template.setUserStatus(userinfoDO.getUserStatus());


        if (UpdateEventTypeEnum.ADD.equals(event.getPassportChanged()) || UpdateEventTypeEnum.UPDATE.equals(event.getPassportChanged())) {
            passportVO = convertPassport(userinfoDO);
            try {
                template.setPassportJson(objectMapper.writeValueAsString(passportVO));
            } catch (Exception e) {
                log.error("UserQueryUpdateListener.onApplicationEvent.passportJson error:{}", e.getMessage());
            }
        }

        if (UpdateEventTypeEnum.ADD.equals(event.getIndividualChanged()) || UpdateEventTypeEnum.UPDATE.equals(event.getIndividualChanged())) {
            individualVO = convertIndividual(userinfoDO.getIndividualId());
            try {
                template.setIndividualJson(objectMapper.writeValueAsString(individualVO));
            } catch (Exception e) {
                log.error("UserQueryUpdateListener.onApplicationEvent.passportJson error:{}", e.getMessage());
            }
        }

        if (UpdateEventTypeEnum.ADD.equals(event.getParticipantChanged()) || UpdateEventTypeEnum.UPDATE.equals(event.getParticipantChanged())) {
            firms = getParticipants(userinfoDO, event.getUserId());
            try {
                template.setParticipantJson(objectMapper.writeValueAsString(firms));
            } catch (Exception e) {
                log.error("UserQueryUpdateListener.onApplicationEvent.passportJson error:{}", e.getMessage());
            }
        }

        if (UpdateEventTypeEnum.ADD.equals(event.getPassportChanged()) || UpdateEventTypeEnum.ADD.equals(event.getParticipantChanged()) || UpdateEventTypeEnum.ADD.equals(event.getIndividualChanged())) {
            template.setCreator(event.getOperator());
        }

        template.setModifier(event.getOperator());
        userQueryService.saveOrUpdate(template);


    }

    public List<FirmVO> getParticipants(UserInfoDO userinfoDO, Long userId) {
        List<FirmVO> ret = new ArrayList<>();

        List<ParticipantInfoDO> participantInfoList = null;
        if (String.valueOf(BaseStatusEnum.AVAILABLE.getCode()).equals(userinfoDO.getUserStatus())) {
            participantInfoList = participantInfoService.findByUserId(userId);
        } else {
            participantInfoList = participantInfoService.findByUserIdIgnoreDisable(userId);
        }

        if (CollectionUtils.isEmpty(participantInfoList)) {
            return null;
        }

        Map<Long, List<ParticipantInfoDO>> participantInfoMap = participantInfoList.stream().collect(Collectors.groupingBy(ParticipantInfoDO::getFirmId));

        for (Map.Entry<Long, List<ParticipantInfoDO>> row : participantInfoMap.entrySet()) {
            Long firmId = row.getKey();
            CustomerFirmDO firmDO = customerFirmService.findById(firmId);
            if (firmDO == null || !firmDO.getId().equals(firmId)) {
                continue;
            }

            FirmVO firm = new FirmVO();
            firm.setCustomerId(firmDO.getCustomerId());
            firm.setFirmCode(firmDO.getFirmCode());
            firm.setFirmName(firmDO.getFirmName());

            List<ParticipantInfoDO> participantInfos = row.getValue();

            if (!CollectionUtils.isEmpty(participantInfos)) {
                firm.setParticipants(new ArrayList<>());

                for (ParticipantInfoDO participantInfo : participantInfos) {
                    ParticipantVO participantVO = new ParticipantVO();
                    participantVO.setParticipantId(participantInfo.getId());
                    participantVO.setScenarioId(participantInfo.getScenarioId());
                    if (participantInfo.getCostCenterId() != null && participantInfo.getCostCenterId() > 0) {
                        CostCenterDO costCenterDO = costCenterService.findById(participantInfo.getCostCenterId());
                        if (costCenterDO != null && costCenterDO.getId().equals(participantInfo.getCostCenterId())) {
                            participantVO.setCostCenterId(costCenterDO.getId());
                            participantVO.setCostCenterCode(costCenterDO.getCostCenterCode());
                            participantVO.setCostCenterName(costCenterDO.getCostCenterName());
                            participantVO.setFirmCostCenterId(firm.getFirmCode() + "_" + costCenterDO.getId());
                            participantVO.setFirmCostCenterCode(firm.getFirmCode() + "_" + costCenterDO.getCostCenterCode());
                        }
                    }

                    participantVO.setRoles(findParticipantRole(userinfoDO, firm, participantVO));

                    firm.getParticipants().add(participantVO);
                }
            }
            ret.add(firm);
        }
        return ret;
    }

    private List<RoleVO> findParticipantRole(UserInfoDO userInfo, FirmVO firm, ParticipantVO participant) {
        List<ParticipantRoleDO> participantRoles = null;
        if (String.valueOf(BaseStatusEnum.AVAILABLE.getCode()).equals(userInfo.getUserStatus())) {
            participantRoles = participantRoleService.findAllByParticipantId(participant.getParticipantId());
        } else {
            participantRoles = participantRoleService.findAllByParticipantIdIgnoreDisable(participant.getParticipantId());
        }

        if (CollectionUtils.isEmpty(participantRoles)) {
            return null;
        }

        List<RoleVO> ret = new ArrayList<>();
        for (ParticipantRoleDO participantRole : participantRoles) {
            RoleInfoDO roleInfo = roleInfoService.findByFirmAndId(firm.getCustomerId(), participantRole.getRoleId());
            if (roleInfo != null) {
                ret.add(convertRole(firm, roleInfo));
            }
        }
        return ret;
    }

    private RoleVO convertRole(FirmVO firm, RoleInfoDO roleInfoDO) {

        if (roleInfoDO == null) {
            return null;
        }

        RoleVO role = new RoleVO();
        role.setRoleId(roleInfoDO.getId());
        role.setRoleName(roleInfoDO.getRoleName());
        role.setRoleCode(roleInfoDO.getRoleCode());
        role.setRoleType(roleInfoDO.getRoleType());

        role.setFirmRoleId(firm.getFirmCode() + "_" + roleInfoDO.getId());
        role.setFirmRoleCode(firm.getFirmCode() + "_" + roleInfoDO.getRoleCode());
        role.setFirmRoleType(firm.getFirmCode() + "_" + roleInfoDO.getRoleType());
        return role;
    }

    private PassportVO convertPassport(UserInfoDO userInfo) {

        if (userInfo == null || userInfo.getId() == null) {
            return null;
        }

        List<UserPassportDO> userPassportList = null;
        if (String.valueOf(BaseStatusEnum.AVAILABLE.getCode()).equals(userInfo.getUserStatus())) {
            userPassportList = userPassportService.findByUserId(userInfo.getId());
        } else {
            userPassportList = userPassportService.findByUserIdIgnoreDisable(userInfo.getId());
        }

        if (userPassportList == null || userPassportList.isEmpty()) {
            return null;
        }

        PassportVO passportVO = new PassportVO();
        for (UserPassportDO userPassport : userPassportList) {

            switch (PassportTypeEnum.getByCode(userPassport.getPassportType())) {
                case USER_NAME:
                    passportVO.setUserName(userPassport.getPassportValue());
                    break;
                case PHONE_NUMBER:
                    passportVO.setPhoneNumber(userPassport.getPassportValue());
                    break;
                case ENT_USER:
                    break;
                case EMP_CODE:
                    passportVO.setEmployeeCode(userPassport.getPassportValue());
                    break;
                case CARD_CODE:
                    passportVO.setCardCode(userPassport.getPassportValue());
                    break;
            }
        }

        return passportVO;

    }

    private IndividualVO convertIndividual(Long individualId) {

        CustomerIndividualDO individualDO = customerIndividualService.findById(individualId);
        if (individualDO == null || !individualDO.getId().equals(individualId)) {
            return null;
        }

        IndividualVO vo = new IndividualVO();
        vo.setCustomerId(individualDO.getCustomerId());
        vo.setCustomerName(individualDO.getCustomerName());

        return vo;
    }

    @Autowired
    private RoleInfoService roleInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserPassportService userPassportService;

    @Autowired
    private ParticipantInfoService participantInfoService;

    @Autowired
    private ParticipantRoleService participantRoleService;

    @Autowired
    private CustomerFirmService customerFirmService;

    @Autowired
    private CustomerIndividualService customerIndividualService;

    @Autowired
    private UserQueryService userQueryService;

    @Autowired
    private CostCenterService costCenterService;
}
